using System;
using System.Diagnostics;
using System.IO;

namespace Dida
{
	public partial class CollisionTriangle
	{
		Vector3D[] verts;

		Plane facePlane;

		/// <summary>
		/// The planes that stand perpendicular on the edges of the triangle.
		/// these planes are facing inwards.
		/// </summary>
		Plane[] edgePlanes;
		/// <summary>
		/// The direction vector of each edge (from it's first vertex 
		/// to it's second vertex).
		/// The length of these vectors is the 1 / the actual distance)
		/// </summary>
		Vector3D[] invEdgeVecs;

		/// <summary>
		/// Creates a CollisionTriangle from the given array of vertices
		/// </summary>
		/// <param name="verts">An array of 3 <see cref = "Vector3D">Vector3D</see>'s
		/// that form a triangle</param>
		public CollisionTriangle(Vector3D[] verts)
		{
			this.verts = verts;

			facePlane = new Plane(verts);
			Debug.Assert(facePlane.normal.SqrLen > 0);

			edgePlanes = new Plane[3];
			invEdgeVecs = new Vector3D[3];
			for (int i = 0; i < 3; i++)
			{
				Vector3D normal = Vector3D.CrossProduct(facePlane.normal,
					verts[(i + 1) % 3] - verts[i]);
				normal.Normalize();
				float dist = -Vector3D.DotProduct(normal, verts[i]);
				edgePlanes[i] = new Plane(normal, dist);

				invEdgeVecs[i] = verts[(i + 1) % 3] - verts[i];
				invEdgeVecs[i] /= invEdgeVecs[i].SqrLen;
			}
		}

		/// <summary>
		/// Creates a 
		/// CollisionTriangle from the given vertices
		/// </summary>
		/// <param name="a">The first vertex of the triangle</param>
		/// <param name="b">The second vertex of the triangle</param>
		/// <param name="c">The third vertex of the triangle</param>
		public CollisionTriangle(Vector3D a, Vector3D b, Vector3D c)
			: this(new Vector3D[] { a, b, c })
		{
		}

		private bool PointInTriangle(Vector3D pt)
		{
			return edgePlanes[0].GetDist(pt) > 0 &&
				edgePlanes[1].GetDist(pt) > 0 &&
				edgePlanes[2].GetDist(pt) > 0;
		}

		/// <summary>
		/// Gets the bounding box of this triangle. The bounding box
		/// is the smallest box that encloses the whole triangle.
		/// </summary>
		public Box BoundingBox
		{
			get
			{
				Box ret = new Box();
				ret.min = verts[0];
				ret.max = verts[0];
				for (int i = 1; i < 3; i++)
				{
					if (verts[i].x < ret.min.x)
						ret.min.x = verts[i].x;
					else if (verts[i].x > ret.max.x)
						ret.max.x = verts[i].x;

					if (verts[i].y < ret.min.y)
						ret.min.y = verts[i].y;
					else if (verts[i].y > ret.max.y)
						ret.max.y = verts[i].y;

					if (verts[i].z < ret.min.z)
						ret.min.z = verts[i].z;
					else if (verts[i].z > ret.max.z)
						ret.max.z = verts[i].z;
				}

				return ret;
			}
		}

		public Plane Plane
		{
			get { return facePlane; }
		}

		/// <summary>
		/// Returns the position of the given vertex.
		/// </summary>
		/// <param name="i">The index of the vertex (0 &lt;= i &lt; 3).</param>
		/// <returns>The position of the vertex.</returns>
		public Vector3D GetVertex(int i)
		{
			return verts[i];
		}

		public void WriteBinary(BinaryWriter writer)
		{
			verts[0].WriteBinary(writer);
			verts[1].WriteBinary(writer);
			verts[2].WriteBinary(writer);
		}

		public void DrawDebug(IGeometryDebugDraw target,UInt32 colour)
		{
			target.DrawLine(verts[0], verts[1],colour);
			target.DrawLine(verts[1], verts[2],colour);
			target.DrawLine(verts[2], verts[0],colour);
		}
	}
}